package com.whately.core.database.interceptor;

import com.whately.core.base.constant.ConstantProject;
import com.whately.core.database.db.WhatelyTxInterceptor;
import com.whately.core.database.common.constant.WhatelyDbConstant;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.interceptor.*;

import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * 事务拦截
 * 开启事务
 */
@Configuration
public class WhatelyTxAspect {

    /*****************************************************************************
     * 全局的事务构造切面
     ****************************************************************************/
    @Bean
    public TransactionInterceptor txAdvice(TransactionManager platformTransactionManager) {
        NameMatchTransactionAttributeSource source = geneTxSource();
        //指定数据源
        WhatelyTxInterceptor whatelyTxInterceptor = new WhatelyTxInterceptor(WhatelyDbConstant.GLOBAL_TX_INTERCEPTOR,platformTransactionManager, source);
        return whatelyTxInterceptor;
    }

    @Bean
    public Advisor txAdviceAdvisor(TransactionManager platformTransactionManager) {
        AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(ConstantProject.GLOBAL_AOP_POINTCUT_EXPRESSION);
        return new DefaultPointcutAdvisor(pointcut, txAdvice(platformTransactionManager));
    }


    private NameMatchTransactionAttributeSource geneTxSource(){
        NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
        /*只读事务，不做更新操作*/
        RuleBasedTransactionAttribute readOnlyTx = new RuleBasedTransactionAttribute();
        readOnlyTx.setReadOnly(true);
        //加上这一行再service嵌套时有坑，参考https://www.cnblogs.com/kevin-yuan/p/9970765.html
        //PROPAGATION_NOT_SUPPORTED事务传播级别5，以非事务运行，如果当前存在事务，则把当前事务挂起
        //PROPAGATION_REQUIRED:事务隔离性为1，若当前存在事务，则加入该事务；如果当前没有事务，则创建一个新的事务。这是默认值。
        //readOnlyTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_NOT_SUPPORTED );

        /*当前存在事务就使用当前事务，当前不存在事务就创建一个新的事务*/
        RuleBasedTransactionAttribute requiredTx = new RuleBasedTransactionAttribute();
        requiredTx.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));

        /*PROPAGATION_REQUIRED:事务隔离性为1，若当前存在事务，则加入该事务；如果当前没有事务，则创建一个新的事务。这是默认值。 */
        requiredTx.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        requiredTx.setTimeout(WhatelyDbConstant.TX_METHOD_TIMEOUT);//如果超过60秒，则回滚事务

        Map<String, TransactionAttribute> txMap = new LinkedHashMap<>();
        //只读事务
        txMap.put("get*", readOnlyTx);
        txMap.put("query*", readOnlyTx);
        txMap.put("is*", readOnlyTx);
        txMap.put("select*", readOnlyTx);

        //正常事务
        txMap.put("add*", requiredTx);
        txMap.put("save*", requiredTx);
        txMap.put("insert*", requiredTx);
        txMap.put("update*", requiredTx);
        txMap.put("delete*", requiredTx);
        txMap.put("submit*", requiredTx);
        txMap.put("*", requiredTx);

        source.setNameMap( txMap );
        return source;
    }

}
